package proj;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;

public class Database {

	public final String UP = "1";
	public final String LOGIN = "2";
	public final String LOGOUT = "3";
	public final String DOWN = "4";

	private String dbDir;
	private String machine;
	private boolean useHeader;
	private int startTime;
	private int window;
	private List<Window> windows;
	private int endTime;

	public Database(String file, boolean useHeader, int startTime, int endTime,
			int window) {
		this.dbDir = "trace/db/"; // Db dir
		this.machine = file; // Set the database
		this.useHeader = useHeader;
		this.startTime = startTime;
		this.endTime = endTime;
		this.window = window;
		this.windows = new LinkedList<Window>();
	}

	public void loadDb() throws IOException {
		LineNumberReader r = new LineNumberReader(new BufferedReader(
				new FileReader(this.dbDir + this.machine)));
		if (useHeader) {
			r.readLine(); // Header
		}

		String line = r.readLine();
		String[] split = line.split(" ");
		int time = Integer.parseInt(split[0]);
		String state = split[1];

		int firstTime = time;
		int i = 0;

		for (; i < firstTime; i += this.window) {
			if (state.equals(DOWN) || state.equals(LOGIN)) {
				this.windows.add(new Window(1));
			} else {
				this.windows.add(new Window(0));
			}
		}

		boolean isUnaviable = false;

		for (; i < this.endTime; i += this.window) {
			while (time < i + this.window) {
				isUnaviable = isUnaviable
						|| (state.equals(DOWN) || state.equals(LOGIN));
				if (r.ready()) {
					line = r.readLine();
					split = line.split(" ");
					time = Integer.parseInt(split[0]);
					state = split[1];
				} else {
					break;
				}
			}

			while (time < this.endTime && time > i + this.window) {
				i++;
				if (isUnaviable) {
					this.windows.add(new Window(0));
				} else {
					this.windows.add(new Window(1));
				}
			}

			isUnaviable = false;

			if (!r.ready()) {
				while (i < this.endTime - this.window) {
					if (state.equals(DOWN) || state.equals(LOGIN)) {
						this.windows.add(new Window(0));
					} else {
						this.windows.add(new Window(1));
					}
					i += this.window;
				}
			}
		}
	}

	public static void artificial_main(String[] args) throws IOException {
		HashSet<Integer> hashs = new HashSet<Integer>();
		FileWriter fw = new FileWriter("artificial.arff");
		int interval = 24 * 7;
		fw.write("@relation 'avail'\n");
		for (int i = 1; i < interval; i++) {
			fw.write(String.format("@attribute T%02d {0,1}\n", i));
		}
		fw.write("@data\n");
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < interval - 1; i++) {
			sb.append((i % 4 == 0 || i % 13 == 0? 1 : 0) + ",");
		}
		for (int i = interval - 1; i < 32000; i++) {
			String s = sb.substring(0, sb.length() - 1).toString();
			if (!hashs.contains(s.hashCode())) {
				fw.write(s + "\n");
				hashs.add(s.hashCode());
			}
			sb.append((i % 4 == 0 || i % 13 == 0? 1 : 0) + ",");
			sb.delete(0, 2);
		}
		fw.close();
	}

	public static void main(String[] args) throws IOException {
		String[] files = new String[] { "02", "04", "05", "06", "08", "09",
				"10", "11", "12", "13", "14", "15", "17", "18", "19", "20",
				"21", "22", "23", "24", "25", "26", "27", "28", "29", "30",
				"31", "32", "33", "34", "37", "38", "39" };
		
		int twoDays = 0;
		//for (twoDays = 0; twoDays < 10; twoDays++) {
			int start = 0; //twoDays*24*2*60;
			int end = 32000; //(twoDays + 1)*24*2*60;
			for (String f : files) {
				HashSet<Integer> hashs = new HashSet<Integer>();
				Database db = new Database(f, true, start, end, 60);
				db.loadDb();
				FileWriter fw = new FileWriter(f + "_" + twoDays +".arff");
				int interval = 24 * 2;
				fw.write("@relation 'avail'\n");
				for (int i = 1; i < interval; i++) {
					fw.write(String.format("@attribute T%02d {0,1}\n", i));
				}
				fw.write("@data\n");
				StringBuilder sb = new StringBuilder();
				for (Window w : db.windows.subList(0, interval - 1)) {
					sb.append(w + ",");
				}
				for (Window w : db.windows.subList(interval - 1, db.windows.size())) {
					String s = sb.substring(0, sb.length() - 1).toString();
					if (!hashs.contains(s.hashCode())) {
						fw.write(s + "\n");
						hashs.add(s.hashCode());
					}
					sb.append(w + ",");
					sb.delete(0, 2);
				}
				fw.close();			
			}
		//}
	}
	
	public static void bd_main(String[] args) throws IOException {
		HashSet<Integer> hashs = new HashSet<Integer>();
		String[] files = new String[] { "02", "04", "05", "06", "08", "09",
				"10", "11", "12", "13", "14", "15", "17", "18", "19", "20",
				"21", "22", "23", "24", "25", "26", "27", "28", "29", "30",
				"31", "32", "33", "34", "37", "38", "39" };
		for (String f : files) {
			Database db = new Database(f, true, 0, 32000, 60);
			db.loadDb();
			FileWriter fw = new FileWriter(f + ".arff");
			int interval = 24 * 7;
			fw.write("@relation 'avail'\n");
			for (int i = 1; i < interval; i++) {
				fw.write(String.format("@attribute T%02d {0,1}\n", i));
			}
			fw.write("@data\n");
			StringBuilder sb = new StringBuilder();
			for (Window w : db.windows.subList(0, interval - 1)) {
				sb.append(w + ",");
			}
			for (Window w : db.windows.subList(interval - 1, db.windows.size())) {
				String s = sb.substring(0, sb.length() - 1).toString();
				if (!hashs.contains(s.hashCode())) {
					fw.write(s + "\n");
					hashs.add(s.hashCode());
				}
				sb.append(w + ",");
				sb.delete(0, 2);
			}
			fw.close();			
		}
	}

	public static void p_main(String[] args) throws IOException {
		Database db = new Database("05", true, 0, 32000, 60);
		db.loadDb();
		FileWriter fw = new FileWriter("02-db");
		int interval = 24 * 2;
		StringBuilder sb = new StringBuilder();
		int cur = 0;
		for (Window w : db.windows) {
			if (cur == interval) {
				cur = 0;
				fw.write(sb.substring(0, sb.length() - 1).toString() + "\n");
				sb = new StringBuilder();
			}
			sb.append(w + ",");
			cur += 1;
		}
		fw.close();
	}

	public List<Window> getWindows() {
		return this.windows;
	}

}